home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / regsub.c < prev    next >
C/C++ Source or Header  |  1996-06-09  |  8KB  |  343 lines

  1. /* vi:set ts=4 sw=4:
  2.  * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  3.  *
  4.  * This is NOT the original regular expression code as written by
  5.  * Henry Spencer. This code has been modified specifically for use
  6.  * with the VIM editor, and should not be used apart from compiling
  7.  * VIM. If you want a good regular expression library, get the
  8.  * original code. The copyright notice that follows is from the
  9.  * original.
  10.  *
  11.  * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  12.  *
  13.  * vim_regsub
  14.  *
  15.  *        Copyright (c) 1986 by University of Toronto.
  16.  *        Written by Henry Spencer.  Not derived from licensed software.
  17.  *
  18.  *        Permission is granted to anyone to use this software for any
  19.  *        purpose on any computer system, and to redistribute it freely,
  20.  *        subject to the following restrictions:
  21.  *
  22.  *        1. The author is not responsible for the consequences of use of
  23.  *                this software, no matter how awful, even if they arise
  24.  *                from defects in it.
  25.  *
  26.  *        2. The origin of this software must not be misrepresented, either
  27.  *                by explicit claim or by omission.
  28.  *
  29.  *        3. Altered versions must be plainly marked as such, and must not
  30.  *                be misrepresented as being the original software.
  31.  *
  32.  * $Log:        regsub.c,v $
  33.  * Revision 1.2  88/04/28  08:11:25  tony
  34.  * First modification of the regexp library. Added an external variable
  35.  * 'reg_ic' which can be set to indicate that case should be ignored.
  36.  * Added a new parameter to vim_regexec() to indicate that the given string
  37.  * comes from the beginning of a line and is thus eligible to match
  38.  * 'beginning-of-line'.
  39.  *
  40.  * Revisions by Olaf 'Rhialto' Seibert, rhialto@mbfys.kun.nl:
  41.  * Changes for vi: (the semantics of several things were rather different)
  42.  * - Added lexical analyzer, because in vi magicness of characters
  43.  *   is rather difficult, and may change over time.
  44.  * - Added support for \< \> \1-\9 and ~
  45.  * - Left some magic stuff in, but only backslashed: \| \+
  46.  * - * and \+ still work after \) even though they shouldn't.
  47.  */
  48.  
  49. #include "vim.h"
  50. #include "globals.h"
  51. #include "proto.h"
  52.  
  53. #ifndef __ARGS
  54. # define __ARGS(a)    a
  55. #endif
  56.  
  57. #include <stdio.h>
  58. #include "regexp.h"
  59.  
  60. #ifdef LATTICE
  61. # include <sys/types.h>        /* for size_t */
  62. #endif
  63.  
  64. #ifndef CHARBITS
  65. #define UCHARAT(p)      ((int)*(char_u *)(p))
  66. #else
  67. #define UCHARAT(p)      ((int)*(p)&CHARBITS)
  68. #endif
  69.  
  70. extern char_u        *reg_prev_sub;
  71.  
  72.     /* This stuff below really confuses cc on an SGI -- webb */
  73. #ifdef __sgi
  74. # undef __ARGS
  75. # define __ARGS(x)    ()
  76. #endif
  77.  
  78.     /*
  79.      * We should define ftpr as a pointer to a function returning a pointer to
  80.      * a function returning a pointer to a function ...
  81.      * This is impossible, so we declare a pointer to a function returning a
  82.      * pointer to a function returning void. This should work for all compilers.
  83.      */
  84. typedef void (*(*fptr) __ARGS((char_u *, int)))();
  85.  
  86. static fptr do_upper __ARGS((char_u *, int));
  87. static fptr do_Upper __ARGS((char_u *, int));
  88. static fptr do_lower __ARGS((char_u *, int));
  89. static fptr do_Lower __ARGS((char_u *, int));
  90.  
  91.     static fptr
  92. do_upper(d, c)
  93.     char_u *d;
  94.     int c;
  95. {
  96.     *d = TO_UPPER(c);
  97.  
  98.     return (fptr)NULL;
  99. }
  100.  
  101.     static fptr
  102. do_Upper(d, c)
  103.     char_u *d;
  104.     int c;
  105. {
  106.     *d = TO_UPPER(c);
  107.  
  108.     return (fptr)do_Upper;
  109. }
  110.  
  111.     static fptr
  112. do_lower(d, c)
  113.     char_u *d;
  114.     int c;
  115. {
  116.     *d = TO_LOWER(c);
  117.  
  118.     return (fptr)NULL;
  119. }
  120.  
  121.     static fptr
  122. do_Lower(d, c)
  123.     char_u *d;
  124.     int c;
  125. {
  126.     *d = TO_LOWER(c);
  127.  
  128.     return (fptr)do_Lower;
  129. }
  130.  
  131. /*
  132.  * regtilde: replace tildes in the pattern by the old pattern
  133.  *
  134.  * Short explanation of the tilde: it stands for the previous replacement
  135.  * pattern. If that previous pattern also contains a ~ we should go back
  136.  * a step further... but we insert the previous pattern into the current one
  137.  * and remember that.
  138.  * This still does not handle the case where "magic" changes. TODO?
  139.  *
  140.  * New solution: The tilde's are parsed once before the first call to
  141.  * vim_regsub(). In the old solution (tilde handled in regsub()) is was
  142.  * possible to get an endless loop.
  143.  */
  144.     char_u *
  145. regtilde(source, magic)
  146.     char_u    *source;
  147.     int        magic;
  148. {
  149.     char_u    *newsub = NULL;
  150.     char_u    *tmpsub;
  151.     char_u    *p;
  152.     int        len;
  153.     int        prevlen;
  154.  
  155.     for (p = source; *p; ++p)
  156.     {
  157.         if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic))
  158.         {
  159.             if (reg_prev_sub)
  160.             {
  161.                     /* length = len(current) - 1 + len(previous) + 1 */
  162.                 prevlen = STRLEN(reg_prev_sub);
  163.                 tmpsub = alloc((unsigned)(STRLEN(source) + prevlen));
  164.                 if (tmpsub)
  165.                 {
  166.                         /* copy prefix */
  167.                     len = (int)(p - source);    /* not including ~ */
  168.                     STRNCPY(tmpsub, source, len);
  169.                         /* interpretate tilde */
  170.                     STRCPY(tmpsub + len, reg_prev_sub);
  171.                         /* copy postfix */
  172.                     if (!magic)
  173.                         ++p;                    /* back off \ */
  174.                     STRCAT(tmpsub + len, p + 1);
  175.  
  176.                     vim_free(newsub);
  177.                     newsub = tmpsub;
  178.                     p = newsub + len + prevlen;
  179.                 }
  180.             }
  181.             else if (magic)
  182.                 STRCPY(p, p + 1);                /* remove '~' */
  183.             else
  184.                 STRCPY(p, p + 2);                /* remove '\~' */
  185.         }
  186.         else if (*p == '\\' && p[1])            /* skip escaped characters */
  187.             ++p;
  188.     }
  189.  
  190.     vim_free(reg_prev_sub);
  191.     if (newsub)
  192.     {
  193.         source = newsub;
  194.         reg_prev_sub = newsub;
  195.     }
  196.     else
  197.         reg_prev_sub = strsave(source);
  198.     return source;
  199. }
  200.  
  201. /*
  202.  - vim_regsub - perform substitutions after a regexp match
  203.  *
  204.  * If copy is TRUE really copy into dest, otherwise dest is not written to.
  205.  *
  206.  * Returns the size of the replacement, including terminating \0.
  207.  */
  208.     int
  209. vim_regsub(prog, source, dest, copy, magic)
  210.     regexp           *prog;
  211.     char_u           *source;
  212.     char_u           *dest;
  213.     int             copy;
  214.     int             magic;
  215. {
  216.     register char_u      *src;
  217.     register char_u      *dst;
  218.     register char_u         *s;
  219.     register int        c;
  220.     register int        no;
  221.     fptr                func = (fptr)NULL;
  222.  
  223.     if (prog == NULL || source == NULL || dest == NULL)
  224.     {
  225.         emsg(e_null);
  226.         return 0;
  227.     }
  228.     if (UCHARAT(prog->program) != MAGIC)
  229.     {
  230.         emsg(e_re_corr);
  231.         return 0;
  232.     }
  233.     src = source;
  234.     dst = dest;
  235.  
  236.     while ((c = *src++) != '\0')
  237.     {
  238.         no = -1;
  239.         if (c == '&' && magic)
  240.             no = 0;
  241.         else if (c == '\\' && *src != NUL)
  242.         {
  243.             if (*src == '&' && !magic)
  244.             {
  245.                 ++src;
  246.                 no = 0;
  247.             }
  248.             else if ('0' <= *src && *src <= '9')
  249.             {
  250.                 no = *src++ - '0';
  251.             }
  252.             else if (vim_strchr((char_u *)"uUlLeE", *src))
  253.             {
  254.                 switch (*src++)
  255.                 {
  256.                 case 'u':    func = (fptr)do_upper;
  257.                             continue;
  258.                 case 'U':    func = (fptr)do_Upper;
  259.                             continue;
  260.                 case 'l':    func = (fptr)do_lower;
  261.                             continue;
  262.                 case 'L':    func = (fptr)do_Lower;
  263.                             continue;
  264.                 case 'e':
  265.                 case 'E':    func = (fptr)NULL;
  266.                             continue;
  267.                 }
  268.             }
  269.         }
  270.         if (no < 0)           /* Ordinary character. */
  271.         {
  272.             if (c == '\\' && *src != NUL)
  273.             {
  274.                 /* Check for abbreviations -- webb */
  275.                 switch (*src)
  276.                 {
  277.                     case 'r':    c = CR;            break;
  278.                     case 'n':    c = NL;            break;
  279.                     case 't':    c = TAB;        break;
  280.                     /* Oh no!  \e already has meaning in subst pat :-( */
  281.                     /* case 'e':    c = ESC;        break; */
  282.                     case 'b':    c = Ctrl('H');    break;
  283.                     default:
  284.                         /* Normal character, not abbreviation */
  285.                         c = *src;
  286.                         break;
  287.                 }
  288.                 src++;
  289.             }
  290.             if (copy)
  291.             {
  292.                 if (func == (fptr)NULL)        /* just copy */
  293.                     *dst = c;
  294.                 else                        /* change case */
  295.                     func = (fptr)(func(dst, c));
  296.                             /* Turbo C complains without the typecast */
  297.             }
  298.             dst++;
  299.         }
  300.         else if (prog->startp[no] != NULL && prog->endp[no] != NULL)
  301.         {
  302.             for (s = prog->startp[no]; s < prog->endp[no]; ++s)
  303.             {
  304.                 if (copy && *s == '\0') /* we hit NUL. */
  305.                 {
  306.                     emsg(e_re_damg);
  307.                     goto exit;
  308.                 }
  309.                 /*
  310.                  * Insert a CTRL-V in front of a CR, otherwise
  311.                  * it will be replaced by a line break.
  312.                  */
  313.                 if (*s == CR)
  314.                 {
  315.                     if (copy)
  316.                     {
  317.                         dst[0] = Ctrl('V');
  318.                         dst[1] = CR;
  319.                     }
  320.                     dst += 2;
  321.                 }
  322.                 else
  323.                 {
  324.                     if (copy)
  325.                     {
  326.                         if (func == (fptr)NULL)        /* just copy */
  327.                             *dst = *s;
  328.                         else                        /* change case */
  329.                             func = (fptr)(func(dst, *s));
  330.                                     /* Turbo C complains without the typecast */
  331.                     }
  332.                     ++dst;
  333.                 }
  334.             }
  335.         }
  336.     }
  337.     if (copy)
  338.         *dst = '\0';
  339.  
  340. exit:
  341.     return (int)((dst - dest) + 1);
  342. }
  343.